跳到主要内容

Promise 常用函数与语法糖

在本章将学到Promise的常用函数与async/await语法糖。

Promise.all

Promise.all 相当于把一堆 promise 请求合并成一个数组,当这个数组全部履行完毕,检查是否全部成功,如果全部成功,则将返回内容合并成一个数组返回给 then 里,如果其中一个失败,则调用 catch 函数。

let p1 = new Promise((resolve, reject) => {
resolve("成功了");
});

let p2 = new Promise((resolve, reject) => {
resolve("success");
});

let p3 = Promse.reject("失败");

Promise.all([p1, p2])
.then((result) => {
console.log(result); //['成功了', 'success']
})
.catch((error) => {
console.log(error);
});

Promise.all([p1, p3, p2])
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error); // 失败了,打出 '失败'
});

Promise.allSettled

与 Promise.All 相似的还有一个 allSettled,allSettled 不追求全部成功,即使在 promise 数组中存在失败的 promise 依然会正常调用 then 函数

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) =>
setTimeout(reject, 100, "foo")
);
const promises = [promise1, promise2];

Promise.allSettled(promises).then((results) =>
results.forEach((result) => console.log(result.status))
);

Promise.race

Promise.race 相当于一个竞速函数,一旦列表中某个 promise 执行完毕了,就会立刻返回第一个执行完毕的内容,需要注意,虽然第一个执行完毕了,但是其他 Promise 依然会正常执行至结束

const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "one");
});

const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "two");
});

Promise.race([promise1, promise2]).then((value) => {
console.log(value);
});
// 输出: "two"

Promise.resolve

Promise.resolve 将一个值包装成一个 Promise 对象,如果这个值是 Promise 则直接返回,如果不是 Promise 则包装成 Promise 对象

Promise.resolve("test");
//输出 Promise { <state>: "fulfilled", <value>: "test" }

Promise.reject

Promise.reject 将一个值包装成一个 Promise 对象,与 resolve 不同的是,这个包装的对象是 rejected 属性

我们可以通过 catch 捕获他的值,如果不进行 catch 捕获,将会提示未捕获错误

Promise.reject("error");
//输出 Promise { <state>: "rejected", <reason>: "error" }
//报错 Uncaught (in promise) error

async 与 await

当执行 Promise 相当于一个异步回调,在他执行后会自动传到 then 上进行处理,那我们有没有办法让他变成同步代码?就是使用 async 与 await

await 后面跟随一个 Promise 会阻塞后续代码的运行,想要使用 await 必须是 async 函数

function resolveAfter2Seconds(x) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}

async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
}
f1();

这里我们声明了一个 f1 函数,为了将 promise 变为同步代码,使用了 await 和 async,直至 resolveAfter2Seconds 返回内容后才会继续执行,并将结果赋值给 x,输出 x。

但当 await 返回的 Promise 是 reject 的时候,不会赋值到 x 上,这时候我们需要用 try...catch 来捕获 reject,在 try内添加可能发生错误的代码段,然后跟随 catch(err),当 try内发生错误的时候就会自动调用 catch 函数捕获错误(有没有很像 Promise 的 catch)

function resolveAfter2Seconds(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(x);
}, 2000);
});
}

async function f1() {
try {
var x = await resolveAfter2Seconds(10);
} catch (err) {
console.log("我发生了错误", err); //这里可以看到catch内捕获了发生错误的值 即10
}
console.log(x); // 10
}
f1();

这样我们就学习了如果将同步包装成异步,但是还需要注意一个问题,当函数加上 async 后,函数也会变成一个 promise 对象。会将返回的值变成 promise 对象的 value

如上方的 f1 函数

const f1Result = f1();
//此时f1Result是一个Promise对象
//当f1彻底结束,f1返回的值会设置到f1Result的value上

也就是说其他函数想要调用 f1 并形成同步代码,那自身也要加上 async,并 await f1 函数

function resolveAfter2Seconds(x) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}

async function f1() {
try {
var x = await resolveAfter2Seconds(10);
} catch (err) {
console.log("我发生了错误", err);
}
return 6666;
}

async function f1await() {
var f1value = await f1();
console.log(f1value);
}

这里我们同步了f1,但是f1await又变成了async函数(这就是async/await的污染性)

那这里就基本讲述完毕了Promise的基本概念了!

如果到这里你全部清楚明白,那你已经很棒了!

最后让我们用一个冷知识结尾。

冷知识

关于全局使用await函数目前还没有实现,但是根据查阅资料,在全局空间使用await有提上日程,可能在以后我们在全局状态下直接await 某个函数也是可以正常执行的。

引用资料

https://www.jianshu.com/p/7e60fc1be1b2

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/race